/*
 * @Author: yooola@foxmail.com
 * @Date: 2024-11-08 22:02:28
 * @LastEditors: yoola youlikesoilove@qq.com
 * @LastEditTime: 2024-12-09 00:19:40
 * @FilePath: \CrabSystemProject\src\ModuleCenter\moduleComm.cc
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置:
 * https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#include "moduleComm.hpp"

// 初始化静态成员
int SerialPortBase::fd = -1;
bool SerialPortBase::port_is_init = false;
std::mutex SerialPortBase::mutex;
Serial_BaudRate SerialPortBase::m_cur_baudrate = Serial_BaudRate::BaudRate_9600;  // 设置默认波特率为9600
std::mutex RS485SerialPortBASE::mutex;
bool RS485SerialPortBASE::m_debug_to_print = false;

uint16_t RS485SerialPortBASE::CRC16_MudBus(uint8_t *puchMsg, uint8_t usDataLen) {
    uint16_t uCRC = 0xffff;  // CRC寄存器

    for (uint8_t num = 0; num < usDataLen; num++) {
        uCRC = (*puchMsg++) ^ uCRC;        // 把数据与16位的CRC寄存器的低8位相异或，结果存放于CRC寄存器。
        for (uint8_t x = 0; x < 8; x++) {  // 循环8次
            if (uCRC & 0x0001) {           // 判断最低位为：“1”
                uCRC = uCRC >> 1;          // 先右移
                uCRC = uCRC ^ 0xA001;      // 再与0xA001异或
            } else {                       // 判断最低位为：“0”
                uCRC = uCRC >> 1;          // 右移
            }
        }
    }
    return uCRC;  // 返回CRC校验值
}

bool RS485SerialPortBASE::get_REGValue(
    const uint16_t &reg_addr,
    const uint16_t &get_Byte_size,
    std::shared_ptr<uint8_t[]> &p_recv_data) {
    std::lock_guard<std::mutex> lock(mutex);                                                // 加锁保护
    memset(m_p_send_data.get(), 0, bufferSize);                                             // 清空发送缓存区
    memset(m_p_recv_data.get(), 0, bufferSize);                                             // 清空接收缓存区
    m_p_send_data[0] = static_cast<uint8_t>(dev_ID & 0xFF);                                 // 设备地址
    m_p_send_data[1] = static_cast<uint8_t>(Func_Reg::READ_SINGLE_DATA_OUTPUT_REG);         // 读取设备
    m_p_send_data[2] = static_cast<uint8_t>((reg_addr >> 8) & 0xFF);                        // 读取寄存器地址前8bit
    m_p_send_data[3] = static_cast<uint8_t>(reg_addr & 0xFF);                               // 寄存器地址后8bit
    m_p_send_data[4] = static_cast<uint8_t>((get_Byte_size >> 8) & 0xFF);                   // 读取数据数量前8bit
    m_p_send_data[5] = static_cast<uint8_t>(get_Byte_size & 0xFF);                          // 读取数据数量后8bit
    uint16_t crc = this->CRC16_MudBus(m_p_send_data.get(), 6);                              // 进行CRC校验
    m_p_send_data[6] = (crc & 0xFF);                                                        // CRC的低八位
    m_p_send_data[7] = ((crc >> 8) & 0xFF);                                                 // CRC的高八位
    SerialPortBase::getInstance().sendData(m_p_send_data, 8);                               // 发送请求数据
    std::this_thread::sleep_for(std::chrono::milliseconds(m_wait_resp_time));               // 等待数据返回
    SerialPortBase::getInstance().receiveData(m_p_recv_data, 5 + get_Byte_size * 2);        // 读取数据
    uint16_t crc_Recv = this->CRC16_MudBus(m_p_recv_data.get(), 5 + m_p_recv_data[2] - 2);  // 进行CRC校验
    if (RS485SerialPortBASE::m_debug_to_print) {
        OUPUT_INFO << m_module_name << " : "
                   << "recv data is: ";
        for (int i = 0; i < 5 + m_p_recv_data[2]; i++) {
            OUPUT_INFO << std::setw(2) << std::setfill('0') << std::hex << static_cast<int>(m_p_recv_data[i]) << " ";
        }
        OUPUT_INFO << std::dec << std::endl;
    }
    if (((crc_Recv >> 8) & 0xFF) != m_p_recv_data[4 + m_p_recv_data[2]] ||
        (crc_Recv & 0xFF) != m_p_recv_data[3 + m_p_recv_data[2]])  // 校验失败
    {
        OUTPUT_ERRR << m_module_name << " : "
                    << "ReadFun : CRC Check failed!!!" << std::endl;
        return false;
    }
    memcpy(p_recv_data.get(), m_p_recv_data.get() + 3, get_Byte_size * 2);

    return true;
}

bool RS485SerialPortBASE::set_REGValue(const uint16_t &reg_addr, const uint16_t &send_data) {
    std::lock_guard<std::mutex> lock(mutex);                                         // 加锁保护
    memset(m_p_send_data.get(), 0, bufferSize);                                      // 清空发送缓存区
    memset(m_p_recv_data.get(), 0, bufferSize);                                      // 清空接收缓存区
    m_p_send_data[0] = static_cast<uint8_t>(dev_ID & 0xFF);                          // 设备地址
    m_p_send_data[1] = static_cast<uint8_t>(Func_Reg::WRITE_SINGLE_DATA_INPUT_REG);  // 读取设备
    m_p_send_data[2] = static_cast<uint8_t>((reg_addr >> 8) & 0xFF);                 // 读取寄存器地址前8bit
    m_p_send_data[3] = static_cast<uint8_t>(reg_addr & 0xFF);                        // 寄存器地址后8bit
    m_p_send_data[4] = static_cast<uint8_t>((send_data >> 8) & 0xFF);                // 读取数据数量前8bit
    m_p_send_data[5] = static_cast<uint8_t>(send_data & 0xFF);                       // 读取数据数量后8bit
    uint16_t crc = this->CRC16_MudBus(m_p_send_data.get(), 6);                       // 进行CRC校验
    m_p_send_data[6] = (crc & 0xFF);                                                 // CRC的低八位
    m_p_send_data[7] = ((crc >> 8) & 0xFF);                                          // CRC的高八位
    SerialPortBase::getInstance().sendData(m_p_send_data, 8);                        // 发送请求数据
    std::this_thread::sleep_for(std::chrono::milliseconds(m_wait_resp_time));        // 等待数据返回
    SerialPortBase::getInstance().receiveData(m_p_recv_data, 8);                     // 读取数据
    if (RS485SerialPortBASE::m_debug_to_print) {
        OUPUT_INFO << m_module_name << " : "
                   << "recv data is: ";
        for (int i = 0; i < 5 + m_p_recv_data[2]; i++) {  // m_p_recv_data[2]是返回有效字节数
            OUPUT_INFO << std::setw(2) << std::setfill('0') << std::hex << static_cast<int>(m_p_recv_data[i]) << " ";
        }
        OUPUT_INFO << std::dec << std::endl;
    }
    uint16_t crc_Recv = this->CRC16_MudBus(m_p_recv_data.get(), 6);                             // 进行CRC校验
    if (((crc_Recv >> 8) & 0xFF) != m_p_recv_data[7] || (crc_Recv & 0xFF) != m_p_recv_data[6])  // 校验失败
    {
        OUTPUT_ERRR << m_module_name << " : "
                    << "SetFunc : CRC Check failed!!!" << std::endl;
        return false;
    }
    return true;
}

bool RS485SerialPortBASE::Get_16bitREGValue(const uint16_t &reg_addr, uint16_t &ret_val) {
    if (get_REGValue(reg_addr, 1, m_p_buffer_data)) {
        ret_val = (((uint16_t)m_p_buffer_data[0] << 8) | (uint16_t)m_p_buffer_data[1]);
        return true;
    } else
        return false;
}

bool RS485SerialPortBASE::Get_32bitREGValue(const uint16_t &reg_addr, uint32_t &ret_val) {
    if (get_REGValue(reg_addr, 2, m_p_buffer_data)) {
        ret_val =
            (((uint32_t)m_p_buffer_data[0] << 24) | ((uint32_t)m_p_buffer_data[1] << 16) |
             ((uint32_t)m_p_buffer_data[2] << 8) | ((uint32_t)m_p_buffer_data[3] << 0));
        return true;
    } else
        return false;
}
